package com.itany.shop.util;

import com.itany.shop.exception.DataAccessException;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

/**
 * @author 石小俊
 * JDBC模板方法:对JDBC访问数据库的操作进行封装
 */
public class JDBCTemplate<T> {

    /**
     * 执行DML操作。即:insert、update、delete
     * 对于DML操作,使用的都是ps.executeUpdate()执行sql
     * 整个操作过程中,仅有sql语句与状态集参数不一致,其他用法都一直
     * 我们可以将不一致的地方封装成方法参数,在具体使用时根据使用场景传递对应的参数
     * @param sql    需要执行的sql语句
     * @param params 执行的sql语句中的参数
     */
    public void update(String sql, Object... params) {
        Connection conn = null;
        PreparedStatement ps = null;
        try {
            conn = JDBCUtil.getConnection();
            ps = conn.prepareStatement(sql);
            // 设置sql参数
            for (int i = 0; i < params.length; i++) {
                ps.setObject(i + 1, params[i]);
//                Object param = params[i];
//                if(param instanceof String){
//                    ps.setString(i+1,(String)param);
//                }
            }
            // 执行DML操作
            ps.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
            throw new DataAccessException("数据访问异常");
        } finally {
            JDBCUtil.close(null, ps, null);
        }
    }

    /**
     * 执行查询操作
     * 查询操作会返回一个结果，其结果可能是一条数据，也可能是多条数据
     * 可以通过一个集合来接收返回的数据
     * 对于查询操作而言，我们需要将返回的结果集映射成Java对象
     * 具体映射成哪一个Java对象，目前不知道。只有当实际调用的时候才能确定
     * 因此，提供一个行映射接口，便于操作返回的数据
     * @param sql    需要执行的sql语句
     * @param rm     行映射，将查询的结果集映射成对象
     * @param params 执行的sql语句中的参数
     * @return 根据行映射结果生成对象集合
     */
    public List<T> query(String sql, RowMapper<T> rm, Object... params) {
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        List<T> list = new ArrayList<>();
        try {
            conn = JDBCUtil.getConnection();
            ps = conn.prepareStatement(sql);
            // 设置sql参数
            for (int i = 0; i < params.length; i++) {
                ps.setObject(i + 1, params[i]);
            }
            // 执行DML操作
            rs = ps.executeQuery();
            while (rs.next()) {
                // 将一行数据映射成一个对象
                T t = rm.mapRow(rs);
                // 每生成一个对象,将该对象添加到对象集合中
                list.add(t);
            }
        } catch (SQLException e) {
            e.printStackTrace();
            throw new DataAccessException("数据访问异常");
        } catch (Exception e) {
            e.printStackTrace();
            throw new DataAccessException("行映射出错");
        } finally {
            JDBCUtil.close(null, ps, null);
        }
        return list;
    }

}
